package com.qs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qs.constant.EsConstant;
import com.qs.constant.RedisConstant;
import com.qs.constant.StatusConstant;
import com.qs.es.service.EsGoodsService;
import com.qs.exception.ServiceException;
import com.qs.mapper.*;
import com.qs.pojo.dto.GoodsDto;
import com.qs.pojo.dto.GoodsIndexVo;
import com.qs.pojo.entity.*;
import com.qs.pojo.es.EsGoodsDto;
import com.qs.response.ResponseEnum;
import com.qs.service.IAsyncService;
import com.qs.service.IGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-11-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GoodsServiceImpl extends  ServiceImpl<GoodsMapper, Goods> implements IGoodsService {

    private final EsGoodsService esGoodsService;

    private final StoreMapper storeMapper;

    private final RedisTemplate redisTemplate;

    private final OrderItemMapper orderItemMapper;

    private final OrderInfoMapper orderInfoMapper;

    private final CategoryMapper categoryMapper;

    private final IAsyncService asyncService;

    @Override
    public Map<String,Object> getList(Integer pageNo, Integer pageSize,Integer storeId) {
        //根据商户id获取商户所属的店铺
        Page<Goods> pageInfo = new Page<>(pageNo, pageSize);
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.eq("store_id",storeId);
        wrapper.orderByDesc("update_time");
        Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
        if(null != goodsPage){
            List<Goods> goods = goodsPage.getRecords();
            List<GoodsDto> list = new ArrayList<GoodsDto>();
            if(!CollectionUtils.isEmpty(goods)){
                goods.stream().forEach(good -> {
                    Store store = storeMapper.selectById(good.getStoreId());
                    GoodsDto goodsDto = new GoodsDto();
                    BeanUtils.copyProperties(good,goodsDto);
                    goodsDto.setKey(good.getId());
                    goodsDto.setStore(store.getHomeName());
                    list.add(goodsDto);
                });
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("data",list);
                map.put("total",goodsPage.getTotal());
                return map;
            }
            return null;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateByKey(GoodsDto goodsDto) {
        QueryWrapper<Store> wrapper = new QueryWrapper<>();
        wrapper.eq("home_name",goodsDto.getStore());
        Store store = storeMapper.selectOne(wrapper);
        goodsDto.setStoreId(store.getId());
        Goods goods = new Goods();
        BeanUtils.copyProperties(goodsDto,goods);
        goods.setId(goodsDto.getKey());
        baseMapper.updateById(goods);
        EsGoodsDto esGoodsDto = new EsGoodsDto();
        BeanUtils.copyProperties(goodsDto,esGoodsDto);
        esGoodsDto.setStoreImage(store.getImage());
        //往es中新增一条商品数据
        try {
            esGoodsService.addDocument(esGoodsDto);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public GoodsDto echo(Integer id) {
        if(null != id) {
            Goods goods = baseMapper.selectById(id);
            Store store = storeMapper.selectById(goods.getStoreId());
            GoodsDto goodsDto = new GoodsDto();
            BeanUtils.copyProperties(goods,goodsDto);
            goodsDto.setKey(goods.getId());
            goodsDto.setStore(store.getHomeName());
            return goodsDto;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatchByIds(List<Integer> ids) {
        List<Goods> goodsList = baseMapper.selectBatchIds(ids);
        //查询要删除的商品中是否有上架的状态
        //如果有需先下架才能删除
        List<Goods> list = goodsList.stream().filter(goods -> goods.getStatus().equalsIgnoreCase(StatusConstant.STATUS_GOODS)).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(list)){
            throw new ServiceException(ResponseEnum.GOODS_DELETE_ERROR);
        }
        //删除
        baseMapper.deleteBatchIds(ids);
        try {
            esGoodsService.deleteDocument(ids, EsConstant.INDEX_NAME_GOODS);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public GoodsDto getDetail(Integer id) {
        if(null != id){
            Goods goods = baseMapper.selectById(id);
            Store store = storeMapper.selectById(goods.getStoreId());
            GoodsDto goodsDto = new GoodsDto();
            BeanUtils.copyProperties(goods,goodsDto);
            goodsDto.setKey(goods.getId());
            goodsDto.setHomeName(store.getHomeName());
            goodsDto.setStoreImage(store.getImage());
            //异步将商品浏览量+1
            asyncService.incrementWithGoods(id);
            return goodsDto;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveGoods(Goods goods) {
        QueryWrapper<Goods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name",goods.getName());
        Goods selectOne = baseMapper.selectOne(queryWrapper);
        if(null != selectOne){
            throw new ServiceException(ResponseEnum.GOODS_NAME_EXITS);
        }

        QueryWrapper<Store> wrapper = new QueryWrapper<>();
        wrapper.eq("home_name",goods.getStore());
        Store store = storeMapper.selectOne(wrapper);
        goods.setStoreId(store.getId());
        baseMapper.insert(goods);

        QueryWrapper<Goods> goodsQueryWrapper = new QueryWrapper<>();
        goodsQueryWrapper.eq("name",goods.getName());
        Goods select = baseMapper.selectOne(goodsQueryWrapper);
        EsGoodsDto esGoodsDto = new EsGoodsDto();
        BeanUtils.copyProperties(select,esGoodsDto);
        esGoodsDto.setKey(select.getId());
        esGoodsDto.setStore(store.getHomeName());
        esGoodsDto.setStoreImage(store.getImage());
        //往es中新增一条商品数据
        try {
            esGoodsService.addDocument(esGoodsDto);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Map<String,Object> backendGoodsList(Integer pageNo, Integer pageSize) throws IOException {
        Page<Goods> pageInfo = new Page<>(pageNo, pageSize);
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.eq("status", StatusConstant.STATUS_GOODS);
        wrapper.orderByDesc("update_time");
        Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
        if(null != goodsPage){
            List<Goods> goodsList = goodsPage.getRecords();
            List<GoodsDto> list = new ArrayList<>();
            if(!CollectionUtils.isEmpty(goodsList)){
                goodsList.stream().forEach(goods -> {
                    Store store = storeMapper.selectById(goods.getStoreId());
                    GoodsDto goodsDto = new GoodsDto();
                    BeanUtils.copyProperties(goods,goodsDto);
                    goodsDto.setKey(goods.getId());
                    goodsDto.setStoreImage(store.getImage());
                    goodsDto.setStoreId(store.getId());
                    goodsDto.setStore(store.getHomeName());
                    list.add(goodsDto);
                });
            }
            if(!CollectionUtils.isEmpty(list)){
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("data",list);
                map.put("total",goodsPage.getTotal());
                return map;
            }
        }
        return null;
    }

    @Override
    public Map<String, Object> getGoodsList(List<Integer> ids,String orderId) {
        if(!CollectionUtils.isEmpty(ids)){
            List<GoodsDto> list = new ArrayList<GoodsDto>(ids.size());
            ids.stream().forEach(goodsId -> {
                GoodsDto goodsDto = new GoodsDto();
                //获取商品
                Goods goods = baseMapper.selectById(goodsId);
                //获取商品对应的店铺
                Store store = storeMapper.selectById(goods.getStoreId());
                QueryWrapper<OrderItem> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("goods_id",goodsId);
                queryWrapper.eq("order_id",orderId);
                OrderItem orderItem = orderItemMapper.selectOne(queryWrapper);
                goodsDto.setKey(goods.getId());
                goodsDto.setStoreId(store.getId());
                goodsDto.setNumber(orderItem.getNumber());
                goodsDto.setStoreImage(store.getImage());
                goodsDto.setHomeName(store.getHomeName());
                goodsDto.setBrand(goods.getBrand());
                goodsDto.setImage(goods.getImage());
                goodsDto.setCategory(goods.getCategory());
                goodsDto.setName(goods.getName());
                goodsDto.setPrice(goods.getPrice());
                goodsDto.setSubTotalPrice(goods.getPrice() * orderItem.getNumber());
                goodsDto.setStatus(goods.getStatus());
                list.add(goodsDto);
            });
            QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
            wrapper.eq("order_id",orderId);
            OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
            Map<String,Object> map = new HashMap<>();
            map.put("data",list);
            map.put("totalPrice",orderInfo.getTotalPrice());
            return map;
        }
        return null;
    }

    @Override
    public List<GoodsIndexVo> getImage() {
        //销量前5的商品数据
        List<GoodsIndexVo> redisData = (List<GoodsIndexVo>) redisTemplate.opsForValue().get(RedisConstant.INDEX_GOODS_IMAGE);
        if (!CollectionUtils.isEmpty(redisData)) {
            return redisData;
        }else{
            Page<Goods> pageInfo = new Page<>(1, 5);
            QueryWrapper<Goods> wrapper = new QueryWrapper<>();
            wrapper.orderByDesc("sale");
            Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
            if(goodsPage != null) {
                List<Goods> goodsList = goodsPage.getRecords();
                List<GoodsIndexVo> list = new ArrayList<>(goodsList.size());
                if(!CollectionUtils.isEmpty(goodsList)){
                    goodsList.stream().forEach(goods -> {
                        GoodsIndexVo goodsIndexVo = new GoodsIndexVo();
                        BeanUtils.copyProperties(goods, goodsIndexVo);
                        list.add(goodsIndexVo);
                    });
                }
                //加入redis缓存
                redisTemplate.opsForValue().set(RedisConstant.INDEX_GOODS_IMAGE,list,RedisConstant.CACHE_EXPIRE,TimeUnit.MINUTES);
                return list;
            }
            return null;
        }
    }

    @Override
    public Map<String, Object> getCategoryGoods(Integer pageNo, Integer pageSize, String categoryName) {
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name",categoryName);
        Category category = categoryMapper.selectOne(queryWrapper);
        //如果是顶级分类，如qs_category表中的数据字段pid为0：则查询它底下的所有分类数据
        if(category.getPid().intValue() == StatusConstant.CATEGORY_PARENT) {
            return getGoodsWithAllCategory(pageNo, pageSize, category);
        }
        Page<Goods> pageInfo = new Page<>(pageNo, pageSize);
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.eq("category", categoryName);
        wrapper.orderByDesc("update_time");
        Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
        if(null != goodsPage){
            List<Goods> goodsList = goodsPage.getRecords();
            List<GoodsDto> list = new ArrayList<GoodsDto>();
            if (!CollectionUtils.isEmpty(goodsList)) {
                goodsList.stream().forEach(good -> {
                    Store store = storeMapper.selectById(good.getStoreId());
                    GoodsDto goodsDto = new GoodsDto();
                    BeanUtils.copyProperties(good, goodsDto);
                    goodsDto.setKey(good.getId());
                    goodsDto.setStore(store.getHomeName());
                    goodsDto.setHomeName(store.getHomeName());
                    goodsDto.setStoreImage(store.getImage());
                    list.add(goodsDto);
                });
            }
            if(!CollectionUtils.isEmpty(list)) {
                Map<String,Object> map = new HashMap<String,Object>(list.size());
                map.put("data",list);
                map.put("total",goodsPage.getTotal());
                return map;
            }
            Map<String,Object> map = new HashMap<String,Object>(list.size());
            map.put("data",null);
            map.put("total",goodsPage.getTotal());
            return map;
        }
        return null;
    }

    private Map<String, Object> getGoodsWithAllCategory(Integer pageNo, Integer pageSize,Category category) {
        Page<Goods> pageInfo = new Page<>(pageNo, pageSize);
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("pid",category.getId());
        List<Category> categories = categoryMapper.selectList(queryWrapper);
        if(!CollectionUtils.isEmpty(categories)) {
            List<String> names = categories.stream().map(Category::getName).collect(Collectors.toList());
            QueryWrapper<Goods> wrapper = new QueryWrapper<>();
            wrapper.in("category",names);
            Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
            if(null != goodsPage){
                List<Goods> goodsList = goodsPage.getRecords();
                List<GoodsDto> list = new ArrayList<GoodsDto>();
                if (!CollectionUtils.isEmpty(goodsList)) {
                    goodsList.stream().forEach(good -> {
                        Store store = storeMapper.selectById(good.getStoreId());
                        GoodsDto goodsDto = new GoodsDto();
                        BeanUtils.copyProperties(good, goodsDto);
                        goodsDto.setKey(good.getId());
                        goodsDto.setStore(store.getHomeName());
                        goodsDto.setHomeName(store.getHomeName());
                        goodsDto.setStoreImage(store.getImage());
                        list.add(goodsDto);
                    });
                }
                if(!CollectionUtils.isEmpty(list)) {
                    Map<String,Object> map = new HashMap<String,Object>(list.size());
                    map.put("data",list);
                    map.put("total",goodsPage.getTotal());
                    return map;
                }
                Map<String,Object> map = new HashMap<String,Object>(list.size());
                map.put("data",null);
                map.put("total",goodsPage.getTotal());
                return map;
            }
        }
        return null;
    }

    @Override
    public List<Integer> frontSearchList(String param,String selectMsg) {
        List<Integer> goodsIds = null;
        try {
            goodsIds = esGoodsService.frontSearchList(param,selectMsg);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return goodsIds;
    }

    @Override
    public Map<String, Object> searchFrontList(Integer pageNo, Integer pageSize, List<Integer> ids,String name) {
        Map<String, Object> map = null;
        try {
            map = esGoodsService.searchGoodsFrontList(pageNo, pageSize, ids,name);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return map;
    }

    @Override
    public List<GoodsDto> frontHotGoodsList(Integer pageNo, Integer pageSize) {
        List<GoodsDto> goodsDtoList = (List<GoodsDto>) redisTemplate.opsForValue().get(RedisConstant.GOODS_HOT);
        if(!CollectionUtils.isEmpty(goodsDtoList)){
            return goodsDtoList;
        }
        Page<Goods> pageInfo = new Page<>(pageNo, pageSize);
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.eq("status", StatusConstant.STATUS_GOODS);
        //根据销量降序排序(获取前30个数据)
        wrapper.orderByDesc("sale");
        Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
        if(null != goodsPage){
            List<Goods> goodsList = goodsPage.getRecords();
            List<GoodsDto> list = new ArrayList<>();
            if(!CollectionUtils.isEmpty(goodsList)){
                goodsList.stream().forEach(goods -> {
                    Store store = storeMapper.selectById(goods.getStoreId());
                    GoodsDto goodsDto = new GoodsDto();
                    BeanUtils.copyProperties(goods,goodsDto);
                    goodsDto.setKey(goods.getId());
                    goodsDto.setStoreImage(store.getImage());
                    goodsDto.setStoreId(store.getId());
                    goodsDto.setStore(store.getHomeName());
                    goodsDto.setBrowse(goods.getBrowse());
                    list.add(goodsDto);
                });
            }
            if(!CollectionUtils.isEmpty(list)){
                //redis缓存
                redisTemplate.opsForValue().set(RedisConstant.GOODS_HOT,list,RedisConstant.GOODS_HOT_CACHE_EXPIRE,TimeUnit.HOURS);
                return list;
            }
        }
        return null;
    }

    @Override
    public List<GoodsDto> frontRecommendGoodsList(Integer pageNo, Integer pageSize) {
        List<GoodsDto> goodsDtoList = (List<GoodsDto>) redisTemplate.opsForValue().get(RedisConstant.GOODS_RECOMMEND);
        if(!CollectionUtils.isEmpty(goodsDtoList)){
            return goodsDtoList;
        }
        Page<Goods> pageInfo = new Page<>(pageNo, pageSize);
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.eq("status", StatusConstant.STATUS_GOODS);
        //根据最新上架时间排序(获取前30个数据)
        wrapper.orderByDesc("create_time");
        Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
        if(null != goodsPage){
            List<Goods> goodsList = goodsPage.getRecords();
            List<GoodsDto> list = new ArrayList<>();
            if(!CollectionUtils.isEmpty(goodsList)){
                goodsList.stream().forEach(goods -> {
                    Store store = storeMapper.selectById(goods.getStoreId());
                    GoodsDto goodsDto = new GoodsDto();
                    BeanUtils.copyProperties(goods,goodsDto);
                    goodsDto.setKey(goods.getId());
                    goodsDto.setStoreImage(store.getImage());
                    goodsDto.setStoreId(store.getId());
                    goodsDto.setStore(store.getHomeName());
                    goodsDto.setBrowse(goods.getBrowse());
                    list.add(goodsDto);
                });
            }
            if(!CollectionUtils.isEmpty(list)){
                //redis缓存
                redisTemplate.opsForValue().set(RedisConstant.GOODS_RECOMMEND,list,RedisConstant.GOODS_RECOMMEND_CACHE_EXPIRE,TimeUnit.HOURS);
                return list;
            }
        }
        return null;
    }

    @Override
    public List<GoodsDto> getLikeGoods(Integer pageNo, Integer pageSize) {
        Page<Goods> pageInfo = new Page<>(pageNo, pageSize);
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("sale");
        Page<Goods> goodsPage = baseMapper.selectPage(pageInfo, wrapper);
        if(null != goodsPage){
            List<Goods> goodsList = goodsPage.getRecords();
            List<GoodsDto> list = new ArrayList<GoodsDto>();
            if (!CollectionUtils.isEmpty(goodsList)) {
                goodsList.stream().forEach(good -> {
                    Store store = storeMapper.selectById(good.getStoreId());
                    GoodsDto goodsDto = new GoodsDto();
                    BeanUtils.copyProperties(good, goodsDto);
                    goodsDto.setKey(good.getId());
                    goodsDto.setStore(store.getHomeName());
                    goodsDto.setHomeName(store.getHomeName());
                    goodsDto.setStoreImage(store.getImage());
                    list.add(goodsDto);
                });
            }
            if(!CollectionUtils.isEmpty(list)) {
                return list;
            }
        }
        return null;
    }

    @Override
    public Map<String, Object> findGoodsNum() {
        //获取上架的商品总数
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.eq("status",StatusConstant.STATUS_GOODS);
        Long count = baseMapper.selectCount(wrapper);
        //获取昨日上架的新增商品总数
        Long yesterdayNum = baseMapper.findStoreYesterday();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("count", count);
        map.put("yesterday",yesterdayNum);
        return map;
    }
}
